#include "main_window.h"
#include <QDebug>
#include <QLabel>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QCheckBox>
#include <QGridLayout>
#include <QDialog>
#include <QFileDialog>
#include <QMessageBox>
#include <QDateTime>
#include <QGroupBox>
#include <QUrl>
#include <QDesktopServices>
#include <QSettings>

QLayout *MainWindow::drawDataShowPanel()
{
    QHBoxLayout *mainLayout;

    mainLayout = new QHBoxLayout();

    rTextShowEdit = new QPlainTextEdit();
    rTextShowEdit->setLineWrapMode(QPlainTextEdit::WidgetWidth);
    rTextShowEdit->setCenterOnScroll(true);
//	rTextShowEdit->setVerticalScrollBar(new QScrollBar(Qt::Vertical));
    mainLayout->addWidget(rTextShowEdit);
    rTextShowEdit->setReadOnly(true);
    rTextShowEdit->setMaximumBlockCount(100000000);
    rHexShowEdit = new HexTextEdit();
    mainLayout->addWidget(rHexShowEdit);
    rHexShowEdit->setReadOnly(true);
    rHexShowEdit->setLineWrapMode(QPlainTextEdit::WidgetWidth);
    rHexShowEdit->setCenterOnScroll(true);
    rHexShowEdit->setHidden(true);
    rHexShowEdit->setMaximumBlockCount(100000000);

    return mainLayout;
}

QLayout *MainWindow::drawConfigPanel()
{
    QVBoxLayout *mainLayout;
    QHBoxLayout *hBoxLayout;
    QPushButton *pushButton;

    mainLayout = new QVBoxLayout();

    hBoxLayout = new QHBoxLayout();
    mainLayout->addLayout(hBoxLayout);
    pushButton = new QPushButton(tr("choose file"));
    hBoxLayout->addWidget(pushButton);
    connect(pushButton, SIGNAL(clicked()), this, SLOT(chooseSendFileSlotFunc()));
    sendFileEdit = new QLineEdit();
    hBoxLayout->addWidget(sendFileEdit);
    sendFileButton = new QPushButton(tr("send file"));
    hBoxLayout->addWidget(sendFileButton);
    connect(sendFileButton, SIGNAL(clicked()), this, SLOT(startSendFileSlotFunc()));
    isSaving = false;
    saveFileButton = new QPushButton(tr("save"));
    connect(saveFileButton, SIGNAL(clicked()), this, SLOT(saveFileSlotFunc()));
    hBoxLayout->addWidget(saveFileButton);
    pushButton = new QPushButton(tr("clear"));
    hBoxLayout->addWidget(pushButton);
    connect(pushButton, SIGNAL(clicked()), this, SLOT(clearRShowEditSlotFunc()));

    hBoxLayout->addStretch();

    showHexCheckBox = new QCheckBox(tr("hex show"));
    hBoxLayout->addWidget(showHexCheckBox);
    connect(showHexCheckBox, SIGNAL(clicked(bool)), this, SLOT(setShowHexSlotFunc(bool)));

    QGridLayout *gridLayout;
    gridLayout = new QGridLayout();
    mainLayout->addLayout(gridLayout);

    gridLayout->addWidget(new QLabel(tr("Serial Port")), 0, 0, 1, 1, Qt::AlignRight);
    serialPortBox = new QComboBox();
    gridLayout->addWidget(serialPortBox, 0, 1, 1, 1);
    foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts())
    {
        serialPortBox->addItem(serialPortInfo.portName());
    }
    connect(serialPortBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(serialPortChangedSlotFunc(QString)));

    openButton = new QPushButton(tr("open"));
    gridLayout->addWidget(openButton, 0, 2, 1, 1, Qt::AlignLeft);
    connect(openButton, SIGNAL(clicked()), this, SLOT(openSerialPortSlotFunc()));

    pushButton = new QPushButton(tr("refresh"));
    gridLayout->addWidget(pushButton, 0, 3, 1, 1, Qt::AlignLeft);
    connect(pushButton, SIGNAL(clicked()), this, SLOT(refreshSerialPortBoxSlotFunc()));

    pushButton = new QPushButton(tr("expand"));
//	pushButton->setDisabled(true);
    pushButton->setCheckable(true);
    pushButton->setChecked(false);
    connect(pushButton, SIGNAL(clicked(bool)), this, SLOT(setExpandPanelEnabled(bool)));
    gridLayout->addWidget(pushButton, 0, 7, 1, 1);


    gridLayout->addWidget(new QLabel(tr("Baud Rate")), 1, 0, 1, 1, Qt::AlignRight);
    baudRateBox = new QComboBox();
    gridLayout->addWidget(baudRateBox, 1, 1, 1, 1);
    baudRateBox->addItem("1200", QSerialPort::Baud1200);
    baudRateBox->addItem("2400", QSerialPort::Baud2400);
    baudRateBox->addItem("4800", QSerialPort::Baud4800);
    baudRateBox->addItem("9600", QSerialPort::Baud9600);
    baudRateBox->addItem("19200", QSerialPort::Baud19200);
    baudRateBox->addItem("38400", QSerialPort::Baud38400);
    baudRateBox->addItem("57600", QSerialPort::Baud57600);
    baudRateBox->addItem("115200", QSerialPort::Baud115200);
    baudRateBox->addItem("230400", 230400);
    baudRateBox->addItem("1000000", 1000000);
    baudRateBox->addItem("1152000", 1152000);
    baudRateBox->addItem("Custom");
    baudRateBox->setCurrentIndex(7);
    connect(baudRateBox, SIGNAL(currentIndexChanged(int)), this, SLOT(baudRateChangedSlotFunc(int)));
    connect(baudRateBox, SIGNAL(editTextChanged(QString)), this, SLOT(serialPortEditTextChangedSlotFunc(QString)));

    gridLayout->addWidget(new QLabel(tr("Data Bits")), 2, 0, 1, 1, Qt::AlignRight);
    dataBitsBox = new QComboBox();
    gridLayout->addWidget(dataBitsBox, 2, 1, 1, 1);
    dataBitsBox->addItem("5", QSerialPort::Data5);
    dataBitsBox->addItem("6", QSerialPort::Data6);
    dataBitsBox->addItem("7", QSerialPort::Data7);
    dataBitsBox->addItem("8", QSerialPort::Data8);
    dataBitsBox->setCurrentIndex(3);
    connect(dataBitsBox, SIGNAL(currentIndexChanged(int)), this, SLOT(dataBitsChangedSlotFunc(int)));

    gridLayout->addWidget(new QLabel(tr("Stop Bits")), 3, 0, 1, 1, Qt::AlignRight);
    stopBitsBox = new QComboBox();
    gridLayout->addWidget(stopBitsBox, 3, 1, 1, 1);
    stopBitsBox->addItem("1", QSerialPort::OneStop);
    stopBitsBox->addItem("1.5", QSerialPort::OneAndHalfStop);
    stopBitsBox->addItem("2", QSerialPort::TwoStop);
    connect(stopBitsBox, SIGNAL(currentIndexChanged(int)), this, SLOT(stopBitsChangedSlotFunc(int)));

    gridLayout->addWidget(new QLabel(tr("Parity")), 4, 0, 1, 1, Qt::AlignRight);
    parityBox = new QComboBox();
    gridLayout->addWidget(parityBox, 4, 1, 1, 1);
    parityBox->addItem("None", QSerialPort::NoParity);
    parityBox->addItem("Even", QSerialPort::EvenParity);
    parityBox->addItem("Odd", QSerialPort::OddParity);
    parityBox->addItem("Mark", QSerialPort::MarkParity);
    parityBox->addItem("Space", QSerialPort::SpaceParity);
    connect(parityBox, SIGNAL(currentIndexChanged(int)), this, SLOT(parityChangedSlotFunc(int)));

    gridLayout->addWidget(new QLabel(tr("Flow Ctrl")), 5, 0, 1, 1, Qt::AlignRight);
    flowControlBox = new QComboBox();
    gridLayout->addWidget(flowControlBox, 5, 1, 1, 1);
    flowControlBox->addItem("None", QSerialPort::NoFlowControl);
    flowControlBox->addItem("RTS/CTS", QSerialPort::HardwareControl);
    flowControlBox->addItem("XON/XOFF", QSerialPort::SoftwareControl);
    connect(flowControlBox, SIGNAL(currentIndexChanged(int)), this, SLOT(flowControlChangedSlotFunc(int)));

    dtrCheckBox = new QCheckBox("DTR");
    connect(dtrCheckBox, SIGNAL(clicked(bool)), this, SLOT(setDtrValue(bool)));
    gridLayout->addWidget(dtrCheckBox, 1, 2, 1, 1);
    rtsCheckBox = new QCheckBox("RTS");
    connect(rtsCheckBox, SIGNAL(clicked(bool)), this, SLOT(setRtsValue(bool)));
    gridLayout->addWidget(rtsCheckBox, 1, 3, 1, 1);
//	QGroupBox *groupBox;
//	QVBoxLayout *vBoxLayout;
//	groupBox = new QGroupBox();
//	vBoxLayout = new QVBoxLayout();
//	vBoxLayout->addWidget(new QLabel(tr("qscom-v1.0")));
//	vBoxLayout->addStretch();
//	vBoxLayout->addWidget(new QLabel(tr("ehome_store@126.com")));
//	QLabel *taobaoLabel;
//	taobaoLabel = new QLabel(tr("taobao: <a href=\"http://shop103223163.taobao.com\">http://shop103223163.taobao.com</a>"));
//	vBoxLayout->addWidget(taobaoLabel);
//	connect(taobaoLabel, SIGNAL(linkActivated(QString)), this, SLOT(openUrl(QString)));
//	groupBox->setLayout(vBoxLayout);
//	gridLayout->addWidget(groupBox, 1, 4, 3, 4);

    intervalBox = new QCheckBox(tr("interval"));
    gridLayout->addWidget(intervalBox, 2, 2, 1, 1);
    connect(intervalBox, SIGNAL(clicked(bool)), this, SLOT(intervalSendSlotFunc(bool)));
    hBoxLayout = new QHBoxLayout();
    gridLayout->addLayout(hBoxLayout, 2, 3, 1, 1);

    intervalLineEdit = new QLineEdit();
    intervalLineEdit->setFixedWidth(50);
//	intervalLineEdit->setInputMask("9");
    intervalLineEdit->setText("100");
    hBoxLayout->addWidget(intervalLineEdit);
    hBoxLayout->addWidget(new QLabel(tr("ms")));


    sendEnterCheckBox = new QCheckBox(tr("\\r"));
    gridLayout->addWidget(sendEnterCheckBox, 3, 2, 1, 1);
    sendEnter = false;
    connect(sendEnterCheckBox, SIGNAL(clicked(bool)), this, SLOT(setSendEnterSlotFunc(bool)));

    sendNewLineCheckBox = new QCheckBox(tr("\\n"));
    gridLayout->addWidget(sendNewLineCheckBox, 3, 3, 1, 1);
    sendNewLine = false;
    connect(sendNewLineCheckBox, SIGNAL(clicked(bool)), this, SLOT(setSendChangeLineSlotFunc(bool)));

    gridLayout->addWidget(new QLabel(tr("Please Input")), 4, 2, 1, 1);
    pushButton = new QPushButton(tr("send"));
    gridLayout->addWidget(pushButton, 4, 7, 1, 1);
    connect(pushButton, SIGNAL(clicked()), this, SLOT(serialPortSendSlotFunc()));

    sendHexCheckBox = new QCheckBox(tr("Hex"));
    gridLayout->addWidget(sendHexCheckBox, 5, 2, 1, 1);
    connect(sendHexCheckBox, SIGNAL(clicked(bool)), this, SLOT(setSendHexSlotFunc(bool)));

    sTextShowEdit = new QLineEdit();
    sTextShowEdit->installEventFilter(this);
    gridLayout->addWidget(sTextShowEdit, 5, 3, 1, 6);
    sHexShowEdit = new HexLineEdit();
    sHexShowEdit->installEventFilter(this);
    gridLayout->addWidget(sHexShowEdit, 5, 3, 1, 6);
    sHexShowEdit->setHidden(true);
    sendHex = false;

    return mainLayout;
}

QLayout *MainWindow::drawSendPanel()
{
    QHBoxLayout *mainLayout;
    QPushButton *pushButton;
    QCheckBox *hexCheckBox;
    QLineEdit *dataLineEdit;
    mainLayout = new QHBoxLayout();


    hexCheckBox = new QCheckBox("Hex");
    mainLayout->addWidget(hexCheckBox);
    dataLineEdit = new QLineEdit();
    mainLayout->addWidget(dataLineEdit);
    dataLineEdit->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    pushButton = new QPushButton("send");
    pushButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
//	connect(pushButton, SIGNAL(clicked()), this, SLOT(sendDataSlotFunc()));
    mainLayout->addWidget(pushButton);

    return mainLayout;
}



QWidget *MainWindow::drawExpandPanel()
{
    QWidget *mainWidget;
    QVBoxLayout *mainLayout;

    mainWidget = new QWidget();
    mainLayout = new QVBoxLayout();
    mainWidget->setLayout(mainLayout);

    mainLayout->addLayout(drawSendPanel());
    mainLayout->addLayout(drawSendPanel());

    mainLayout->addLayout(drawSendPanel());
    mainLayout->addLayout(drawSendPanel());

    mainLayout->addLayout(drawSendPanel());
    mainLayout->addLayout(drawSendPanel());

    mainLayout->addLayout(drawSendPanel());
    mainLayout->addLayout(drawSendPanel());

    mainLayout->addLayout(drawSendPanel());
    mainLayout->addLayout(drawSendPanel());

    mainLayout->addLayout(drawSendPanel());
    mainLayout->addLayout(drawSendPanel());

    mainLayout->addLayout(drawSendPanel());
    mainLayout->addLayout(drawSendPanel());

    mainLayout->addLayout(drawSendPanel());
    mainLayout->addLayout(drawSendPanel());

    mainLayout->addStretch();

    return mainWidget;
}

QLayout *MainWindow::drawStatusPanel()
{
    QHBoxLayout *mainLayout;

    mainLayout = new QHBoxLayout();
    serialPortInfo = new QLabel(tr("not open"));
    mainLayout->addWidget(serialPortInfo);
    mainLayout->addStretch(1);

    mainLayout->addWidget(new QLabel(tr("recv:")));
    recvLabel = new QLabel("0");
    mainLayout->addWidget(recvLabel);

    mainLayout->addWidget(new QLabel(tr("send:")));
    sendLabel = new QLabel("0");
    mainLayout->addWidget(sendLabel);

    connect(&serialPort, SIGNAL(readyRead()), this, SLOT(serialPortRecvSlotFunc()));
    connect(&serialPort, SIGNAL(bytesWritten(qint64)), this, SLOT(processSerialPortSendFinished(qint64)));
    connect(this, SIGNAL(sendFileSignal(qint64)), this, SLOT(sendFileSlotFunc(qint64)));
    recvCount = 0;
    sendCount = 0;

    return mainLayout;
}

void MainWindow::setExpandPanelEnabled(bool enabled)
{
    expandPanel->setHidden(!enabled);
}


MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{
    QVBoxLayout *mainLayout;
    QHBoxLayout *upLayout;
    QVBoxLayout *leftLayout;

    this->setWindowTitle(tr("qscom-v1.1"));
    mainLayout = new QVBoxLayout();
    this->setLayout(mainLayout);

    showHex = false;
    upLayout = new QHBoxLayout();
    mainLayout->addLayout(upLayout);

    leftLayout = new QVBoxLayout();
    upLayout->addLayout(leftLayout);

    leftLayout->addLayout(drawDataShowPanel());
    leftLayout->addLayout(drawConfigPanel());
    expandPanel = drawExpandPanel();
    upLayout->addWidget(expandPanel);
    setExpandPanelEnabled(false);
    mainLayout->addLayout(drawStatusPanel());

    readSettings();
    setDtrValue(dtrCheckBox->isChecked());
    setRtsValue(rtsCheckBox->isChecked());
    setShowHexSlotFunc(showHex);
    setSendHexSlotFunc(sendHex);
    connect(&serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(processSerialPortError(QSerialPort::SerialPortError)));
}

MainWindow::~MainWindow()
{

}
bool MainWindow::openSerialPort(const QString &name)
{
    serialPort.setPortName(name);
    if(serialPort.open(QIODevice::ReadWrite))
    {
        serialPort.clear();

        int baud = customBaudRate;
        if(baudRateBox->currentIndex() != baudRateBox->count() - 1)
        {
            baud = baudRateBox->itemData(baudRateBox->currentIndex()).toInt();
        }
        if(serialPort.setBaudRate(static_cast<QSerialPort::BaudRate>(baud))
                && serialPort.setDataBits(static_cast<QSerialPort::DataBits>(dataBitsBox->itemData(dataBitsBox->currentIndex()).toInt()))
                && serialPort.setStopBits(static_cast<QSerialPort::StopBits>(stopBitsBox->itemData(stopBitsBox->currentIndex()).toInt()))
                && serialPort.setParity(static_cast<QSerialPort::Parity>(parityBox->itemData(parityBox->currentIndex()).toInt()))
                && serialPort.setFlowControl(static_cast<QSerialPort::FlowControl>(flowControlBox->itemData(flowControlBox->currentIndex()).toInt())))
        {
            serialPortInfo->setText(tr("dev: ")+name+tr(",    baud: ")+baudRateBox->currentText());
            setDtrValue(dtrCheckBox->isChecked());
            setRtsValue(rtsCheckBox->isChecked());
            return true;
        }
        else
        {
            QMessageBox::critical(this, tr("failed to config serial port"), serialPort.errorString());
        }
    }
    else
    {
        QMessageBox::critical(this, tr("failed to open serial port"), serialPort.errorString());
    }
    closeSerialPort();

    return false;
}
void MainWindow::closeSerialPort()
{
    serialPort.close();
    openButton->setText(tr("open"));
    serialPortInfo->setText(tr("dev: null,    baud: null"));
}

void MainWindow::readSettings()
{
    int index;
    QSettings settings("ehome store", "qscom");

    settings.beginGroup("Serial Port");
    index = serialPortBox->findText(settings.value("Name").toString());
    if(index > 0)
    {
        serialPortBox->setCurrentIndex(index);
    }
    index = baudRateBox->findText(settings.value("Baud").toString());
    if(index > 0)
    {
        baudRateBox->setCurrentIndex(index);
    }
    index = dataBitsBox->findText(settings.value("Data Bits").toString());
    if(index > 0)
    {
        dataBitsBox->setCurrentIndex(index);
    }
    index = stopBitsBox->findText(settings.value("Stop Bits").toString());
    if(index > 0)
    {
        stopBitsBox->setCurrentIndex(index);
    }
    index = parityBox->findText(settings.value("Parity").toString());
    if(index > 0)
    {
        parityBox->setCurrentIndex(index);
    }
    index = flowControlBox->findText(settings.value("Flow Ctrl").toString());
    if(index > 0)
    {
        flowControlBox->setCurrentIndex(index);
    }
    dtrCheckBox->setChecked(settings.value("DTR").toBool());
    rtsCheckBox->setChecked(settings.value("RTS").toBool());

    settings.endGroup();

    settings.beginGroup("Recv");
    showHexCheckBox->setChecked(settings.value("Hex Show").toBool());
    showHex = showHexCheckBox->isChecked();
    settings.endGroup();

    settings.beginGroup("Send");
    intervalBox->setChecked(settings.value("Interval").toBool());
    intervalLineEdit->setText(settings.value("Interval Time MS").toString());
    sendHexCheckBox->setChecked(settings.value("Hex Show").toBool());
    sendHex = sendHexCheckBox->isChecked();
    sendEnterCheckBox->setChecked(settings.value("Enter").toBool());
    sendEnter = sendEnterCheckBox->isChecked();
    sendNewLineCheckBox->setChecked(settings.value("New Line").toBool());
    sendNewLine = sendNewLineCheckBox->isChecked();
    sTextShowEdit->setText(settings.value("Ascii Text").toString());
    sHexShowEdit->setText(settings.value("Hex Text").toString());
    settings.endGroup();
}

void MainWindow::writeSettings()
{
    QSettings settings("ehome store", "qscom");

    settings.beginGroup("Serial Port");
    settings.setValue("Name", serialPortBox->currentText());
    settings.setValue("Baud", baudRateBox->currentText());
    settings.setValue("Data Bits", dataBitsBox->currentText());
    settings.setValue("Stop Bits", stopBitsBox->currentText());
    settings.setValue("Parity", parityBox->currentText());
    settings.setValue("Flow Ctrl", flowControlBox->currentText());
    settings.setValue("DTR", dtrCheckBox->isChecked());
    settings.setValue("RTS", rtsCheckBox->isChecked());
    settings.endGroup();

    settings.beginGroup("Recv");
    settings.setValue("Hex Show", showHexCheckBox->isChecked());
    settings.endGroup();

    settings.beginGroup("Send");
    settings.setValue("Interval", intervalBox->isChecked());
    settings.setValue("Interval Time MS", intervalLineEdit->text());
    settings.setValue("Hex Show", sendHexCheckBox->isChecked());
    settings.setValue("Enter", sendEnterCheckBox->isChecked());
    settings.setValue("New Line", sendNewLineCheckBox->isChecked());
    settings.setValue("Ascii Text", sTextShowEdit->text());
    settings.setValue("Hex Text", sHexShowEdit->text());
    settings.endGroup();
}

void MainWindow::processSerialPortSendFinished(qint64 byteNum)
{
    sendCount += byteNum;
    sendLabel->setText(QString::number(sendCount));
}

void MainWindow::processSerialPortError(QSerialPort::SerialPortError error)
{
    if(serialPort.isOpen() && error == QSerialPort::ResourceError) {
        serialPort.close();
        openButton->setText(tr("open"));
        QMessageBox::critical(this, tr("Ctrl Error"), tr("serial port is missed!"));
    }
}

void MainWindow::openSerialPortSlotFunc()
{
    if(serialPort.isOpen())
    {
        closeSerialPort();
    }
    else
    {
        if(openSerialPort(serialPortBox->currentText()))
        {
            openButton->setText(tr("close"));
        }
    }
}

void MainWindow::refreshSerialPortBoxSlotFunc()
{
    disconnect(serialPortBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(serialPortChangedSlotFunc(QString)));
    QString curStr = serialPortBox->currentText();
    serialPortBox->clear();
    foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts())
    {
        serialPortBox->addItem(serialPortInfo.portName());
    }
    int index = serialPortBox->findText(curStr);
    if(index < 0)
    {
        if(serialPort.isOpen())
        {
            closeSerialPort();
        }
        QMessageBox::warning(this, tr("failed to find serial port"), tr("can't find the serial port: ")+curStr);
        connect(serialPortBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(serialPortChangedSlotFunc(QString)));
        serialPortBox->setCurrentIndex(0);

    }
    else
    {
        serialPortBox->setCurrentIndex(index);
        connect(serialPortBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(serialPortChangedSlotFunc(QString)));
    }
}

void MainWindow::clearRShowEditSlotFunc()
{
    recvCount = 0;
    sendCount = 0;
    rTextShowEdit->clear();
    rHexShowEdit->clear();
    recvLabel->setText("0");
    sendLabel->setText("0");
}

void MainWindow::serialPortEditTextChangedSlotFunc(const QString &text)
{
    bool ok=false;
    customBaudRate = text.toInt(&ok);
    if(!ok)
    {
        customBaudRate = -1;
    }
}
void MainWindow::serialPortRecvSlotFunc()
{
    QByteArray data;
    QTextCursor textCursor;

    data = serialPort.readAll();
    if(!data.isEmpty())
    {
        recvCount += data.length();
        recvLabel->setText(QString::number(recvCount));

        rHexShowEdit->appendByteArray(data);

        QString text;
        int cnt=0, len=data.length();
        while(cnt < len)
        {
            if(!data.at(cnt))
            {
#if defined(USING_NULL_STR)
                data.replace(cnt++, 1, "(");
                data.insert(cnt, "null)");
                cnt = cnt + 5;
                len = len + 5;
#else
                data.remove(cnt, 1);
                len--;
#endif
            }
            else
            {
                cnt++;
            }
        }
        text.append(data);
        textCursor = rTextShowEdit->textCursor();
        textCursor.movePosition(QTextCursor::End);
        rTextShowEdit->setTextCursor(textCursor);
        rTextShowEdit->insertPlainText(text);
    }
}
void MainWindow::serialPortSendSlotFunc()
{
    bool ok;
    QByteArray data;

    if(serialPort.isOpen())
    {
        if(!sendHex)
        {
            data = sTextShowEdit->text().toLatin1();
        }
        else
        {
            data = sHexShowEdit->hexText(&ok);
            if(!ok)
            {
                intervalBox->setChecked(false);
                intervalSendSlotFunc(false);
                return;
            }
        }
        if(sendEnter)
        {
            data.append("\r");
        }
        if(sendNewLine)
        {
            data.append("\n");
        }
        uint len = data.length();
        if(len > 0)
        {
            if(serialPort.write(data) <= 0)
            {
                closeSerialPort();
                QMessageBox::critical(this, tr("failed to write serial port"), serialPort.errorString());
            }
        }
    }
}
void MainWindow::chooseSendFileSlotFunc(void)
{
    sendFileEdit->setText(QFileDialog::getOpenFileName(this, tr("Choose file to send")));
}
void MainWindow::startSendFileSlotFunc(void)
{
    if(!sendFile.isOpen())
    {
        if(serialPort.isOpen())
        {
            sendFile.setFileName(sendFileEdit->text());
            if(sendFile.open(QIODevice::ReadOnly))
            {
                sendFileData.clear();
                connect(&serialPort, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFileSlotFunc(qint64)));
                sendFileButton->setText(tr("stop send"));
                emit sendFileSignal(0);
            }
            else
            {
                QMessageBox::critical(this, tr("failed open file"), sendFile.errorString());
            }
        }
    }
    else
    {
        disconnect(&serialPort, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFileSlotFunc(qint64)));
        sendFile.close();
        sendFileButton->setText(tr("send file"));
    }
}
void MainWindow::sendFileSlotFunc(qint64 len)
{
    if(sendFile.isOpen())
    {
        if(serialPort.isOpen())
        {
            if(sendFile.atEnd())
            {
                disconnect(&serialPort, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFileSlotFunc(qint64)));
                sendFile.close();
                sendFileButton->setText(tr("send file"));
            }
            if(len < sendFileData.length())
            {
                sendFileData.remove(0, len);
                sendFileData = sendFileData + sendFile.read(len);
            }
            else
            {
                sendFileData = sendFile.read(512);
            }
            serialPort.write(sendFileData);
        }
        else
        {
            disconnect(&serialPort, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFileSlotFunc(qint64)));
            sendFile.close();
            sendFileButton->setText(tr("send file"));
        }
    }
}
void MainWindow::saveFileSlotFunc()
{
    if(!saveFile.isOpen())
    {
        QDateTime time = QDateTime::currentDateTime();
        QString filename = QDir::homePath()+"/"+time.toString("yyyy-MM-dd_hh-mm-ss")+"_";
        if(serialPort.portName().isNull())
        {
            filename += "unknow";
        }
        else
        {
            filename += serialPort.portName();
        }
        filename += ".dat";
        saveFile.setFileName(filename);
        if(!saveFile.open(QIODevice::WriteOnly))
        {
            QMessageBox::critical(this, tr("failed open file"), saveFile.errorString());
            return;
        }
        if(!showHex)
        {
            saveFile.write(rTextShowEdit->toPlainText().toLatin1());
        }
        else
        {
            saveFile.write(rHexShowEdit->toPlainText().toLatin1());
        }
        saveFile.close();
        QMessageBox::information(this, NULL, tr("Save file ")+saveFile.fileName()+tr(" succesfully!"));
    }
}

void MainWindow::setShowHexSlotFunc(bool showHex)
{
    this->showHex = showHex;
    rTextShowEdit->setHidden(this->showHex);
    rHexShowEdit->setVisible(this->showHex);
}
void MainWindow::setSendEnterSlotFunc(bool enter)
{
    this->sendEnter = enter;
}
void MainWindow::setSendChangeLineSlotFunc(bool changeLine)
{
    this->sendNewLine = changeLine;
}
void MainWindow::setSendHexSlotFunc(bool sendHex)
{
    this->sendHex = sendHex;
    if(this->sendHex)
    {
        sTextShowEdit->setHidden(true);
        sHexShowEdit->setVisible(true);
    }
    else
    {
        sHexShowEdit->setHidden(true);
        sTextShowEdit->setVisible(true);
    }
}
void MainWindow::serialPortChangedSlotFunc(QString text)
{
    if(serialPort.isOpen())
    {
        serialPort.close();
        openSerialPort(text);
    }
}

void MainWindow::baudRateChangedSlotFunc(int index)
{
    if(index == baudRateBox->count()-1)
    {
        baudRateBox->setEditable(true);
    }
    else
    {
        baudRateBox->setEditable(false);
//        baudRateBox->set
    }
    if(serialPort.isOpen())
    {
        if(!serialPort.setBaudRate(static_cast<QSerialPort::BaudRate>(baudRateBox->itemData(index).toInt())))
        {
            closeSerialPort();
            QMessageBox::critical(this, tr("failed to config serial port"), serialPort.errorString());
        }
        else
        {
            serialPortInfo->setText(tr("dev: ")+serialPort.portName()+tr(",    baud: ")+baudRateBox->currentText());
        }
    }
}
void MainWindow::dataBitsChangedSlotFunc(int index)
{
    if(serialPort.isOpen())
    {
        if(!serialPort.setDataBits(static_cast<QSerialPort::DataBits>(dataBitsBox->itemData(index).toInt())))
        {
            closeSerialPort();
            QMessageBox::critical(this, tr("failed to config serial port"), serialPort.errorString());
        }
    }
}
void MainWindow::stopBitsChangedSlotFunc(int index)
{
    if(serialPort.isOpen())
    {
        if(!serialPort.setStopBits(static_cast<QSerialPort::StopBits>(stopBitsBox->itemData(index).toInt())))
        {
            closeSerialPort();
            QMessageBox::critical(this, tr("failed to config serial port"), serialPort.errorString());
        }
    }
}
void MainWindow::parityChangedSlotFunc(int index)
{
    if(serialPort.isOpen())
    {
        if(!serialPort.setParity(static_cast<QSerialPort::Parity>(parityBox->itemData(index).toInt())))
        {
            closeSerialPort();
            QMessageBox::critical(this, tr("failed to config serial port"), serialPort.errorString());
        }
    }
}
void MainWindow::flowControlChangedSlotFunc(int index)
{
    if(serialPort.isOpen())
    {
        if(!serialPort.setFlowControl(static_cast<QSerialPort::FlowControl>(flowControlBox->itemData(index).toInt())))
        {
            closeSerialPort();
            QMessageBox::critical(this, tr("failed to config serial port"), serialPort.errorString());
        }
    }
}
void MainWindow::intervalSendSlotFunc(bool check)
{
    if(!check)
    {
        sendTimer.stop();
        disconnect(&sendTimer, SIGNAL(timeout()), this, SLOT(serialPortSendSlotFunc()));
    }
    else
    {
        bool ok;
        uint interval=intervalLineEdit->text().toUInt(&ok, 10);
        if(ok)
        {
            connect(&sendTimer, SIGNAL(timeout()), this, SLOT(serialPortSendSlotFunc()));
            sendTimer.setInterval(interval);
            sendTimer.start();
        }
        else
        {
            QMessageBox::critical(this, tr("interval data error"), tr("failed to get interval data"));
            intervalBox->setChecked(false);
        }
    }
}

void MainWindow::openUrl(QString url)
{
    QDesktopServices::openUrl(QUrl(url));
}

void MainWindow::setDtrValue(bool value)
{
    if(serialPort.isOpen())
    {
        serialPort.setDataTerminalReady(value);
    }
}

void MainWindow::setRtsValue(bool value)
{
    if(serialPort.isOpen())
    {
        serialPort.setRequestToSend(value);
    }
}

bool MainWindow::eventFilter(QObject *obj, QEvent *e)
{
    if((obj==sTextShowEdit||obj==sHexShowEdit) && e->type()==QEvent::KeyPress)
    {
        QKeyEvent *event = static_cast<QKeyEvent*>(e);
        if(event->key()==Qt::Key_Return || event->key()==Qt::Key_Enter)
        {
            serialPortSendSlotFunc();
            return true;
        }
    }
    return false;
}

void MainWindow::closeEvent(QCloseEvent *event)
{

    writeSettings();
    event->accept();
}
